<template>
  <div class="timeline-area" ref="timelineAreaRef" @scroll="handleTimelineScroll">
    <div class="timeline-content" :style="{ width: totalWidth + 'px', minWidth: totalWidth + 'px' }">
      <!-- 时间轴表头 -->
      <div class="timeline-header-row" :style="{ width: totalWidth + 'px' }">
        <div 
          v-for="(unit, index) in (timelineUnits || [])" 
          :key="`${viewType}-${index}`"
          class="timeline-unit-header"
          :style="{ width: unitWidth + 'px' }"
        >
          <div class="unit-label">
            <span>{{ unit.label }}</span>
          </div>
          <div v-if="viewType === 'day'" class="unit-sub-label">{{ unit.dayOfWeek }}</div>
          <div v-if="viewType === 'week'" class="unit-sub-label">第{{ unit.weekNumber }}周</div>
        </div>
      </div>
      
      <!-- 时间轴内容 -->
      <div class="timeline-content-area" :style="{ 
        width: totalWidth + 'px', 
        '--unit-width': unitWidth + 'px',
        height: (tasks && tasks.length || 0) * 50 + 'px'
      }">
        <!-- 依赖连线 -->
        <svg 
          v-if="showDependencyLines"
          class="dependency-lines"
          :width="totalWidth"
          :height="(tasks && tasks.length || 0) * 50"
        >
          <defs>
            <marker
              id="arrowhead"
              markerWidth="10"
              markerHeight="7"
              refX="9"
              refY="3.5"
              orient="auto"
            >
              <polygon points="0 0, 10 3.5, 0 7" fill="#409EFF" />
            </marker>
          </defs>
          <path
            v-for="line in (dependencyLines || [])"
            :key="line.id"
            :d="line.path"
            stroke="#409EFF"
            stroke-width="2"
            fill="none"
            marker-end="url(#arrowhead)"
            opacity="0.7"
          />
        </svg>
        
        <!-- 任务条 -->
        <div 
          v-for="(task, index) in (tasks || [])" 
          :key="task.id"
          class="task-bar-container"
          :style="{ 
            height: '50px',
            top: index * 50 + 'px',
            position: 'absolute',
            left: '0',
            right: '0'
          }"
        >
          <div
            class="task-bar"
            :class="{ 'dragging': dragState.isDragging && dragState.draggedTask?.id === task?.id }"
            :style="getTaskBarStyle(task)"
            @mousedown="startDrag($event, task, 'move')"
            @dblclick="selectTask(task)"
            @mouseenter="showTooltip($event, task)"
            @mouseleave="hideTooltip"
          >
            <div class="task-bar-content">
              <span class="task-name">{{ task?.name || '未知任务' }}</span>
              <span class="task-progress">{{ task?.progress || 0 }}%</span>
            </div>
            <!-- 进度条容器 -->
            <div class="task-progress-container">
              <div 
                class="task-progress-fill"
                :style="{ 
                  width: (task?.progress || 0) + '%'
                }"
              ></div>
            </div>
            
            <!-- 大小调整手柄 -->
            <div 
              class="resize-handle resize-start"
              @mousedown.stop="startDrag($event, task, 'resize-start')"
            ></div>
            <div 
              class="resize-handle resize-end"
              @mousedown.stop="startDrag($event, task, 'resize-end')"
            ></div>
          </div>
        </div>
        
        <!-- 今天线 -->
        <div 
          v-if="showToday"
          class="today-line"
          :style="{ 
            left: todayLinePosition + 'px',
            height: (tasks && tasks.length || 0) * 50 + 'px'
          }"
        ></div>
        
        <!-- 时间范围指示器 -->
        <div 
          v-if="showTimeRangeIndicator"
          class="time-range-indicator"
          :style="{ 
            left: timeRangeIndicatorLeft + 'px',
            width: timeRangeIndicatorWidth + 'px',
            height: (tasks && tasks.length || 0) * 50 + 'px'
          }"
        ></div>
        
        <!-- 任务提示框 -->
        <TaskTooltip
          :visible="tooltip.visible"
          :task="tooltip.task"
          :style="tooltip.style"
          :all-tasks="allTasks"
        />
      </div>
    </div>
  </div>
</template>

<script>
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import dayjs from 'dayjs'
import minMax from 'dayjs/plugin/minMax'
import isoWeek from 'dayjs/plugin/isoWeek'
import TaskTooltip from './TaskTooltip.vue'

dayjs.extend(minMax)
dayjs.extend(isoWeek)

export default {
  name: 'GanttTimeline',
  components: {
    TaskTooltip
  },
  props: {
    tasks: {
      type: Array,
      required: true
    },
    allTasks: {
      type: Array,
      required: true
    },
    timelineStart: {
      type: Object,
      required: true
    },
    timelineEnd: {
      type: Object,
      required: true
    },
    viewType: {
      type: String,
      default: 'day', // 'day' | 'week'
      validator: (value) => ['day', 'week'].includes(value)
    },
    zoomLevel: {
      type: Number,
      default: 1
    },
    showToday: {
      type: Boolean,
      default: true
    },
    showDependencyLines: {
      type: Boolean,
      default: true
    },
    timeRange: {
      type: Array,
      default: null
    },
    dragState: {
      type: Object,
      default: () => ({
        isDragging: false,
        dragType: null,
        draggedTask: null,
        startX: 0,
        startY: 0,
        originalStartDate: null,
        originalEndDate: null,
        autoScrollInterval: null,
        tempEndDate: null,
        tempStartDate: null
      })
    },
    taskListScrollTop: {
      type: Number,
      default: 0
    }
  },
  emits: ['scroll', 'task-select', 'task-drag-start', 'task-drag-move', 'task-drag-end', 'tooltip-show', 'tooltip-hide'],
  setup(props, { emit }) {
    const timelineAreaRef = ref(null)
    
    // 悬浮提示状态
    const tooltip = ref({
      visible: false,
      task: null,
      style: {
        left: '0px',
        top: '0px'
      }
    })
    
    // 计算时间轴单位
    const timelineUnits = computed(() => {
      if (props.viewType === 'week') {
        // 周视图：按周分组
        const weeks = []
        let currentWeek = props.timelineStart ? props.timelineStart.clone() : dayjs();
        
        while (currentWeek.isBefore(props.timelineEnd) || currentWeek.isSame(props.timelineEnd, 'week')) {
          // 确保从周一开始
          const weekStart = currentWeek.clone().startOf('week')
          // 周结束时间是周日
          const weekEnd = weekStart.clone().endOf('week')
          // 使用 isoWeek() 方法获取周数
          const weekNumber = weekStart.isoWeek()
          weeks.push({
            start: weekStart,
            end: weekEnd,
            label: `${weekStart.format('MM-DD')} ~ ${weekEnd.format('MM-DD')}`,
            weekNumber: weekNumber.toString()
          })
          currentWeek = currentWeek.add(1, 'week')
        }
        return weeks
      } else {
        // 日视图：按天显示
        const days = []
        let currentDate = props.timelineStart ? props.timelineStart.clone() : dayjs();
        while (currentDate.isBefore(props.timelineEnd) || currentDate.isSame(props.timelineEnd, 'day')) {
          days.push({
            start: currentDate.clone(),
            end: currentDate.clone(),
            label: currentDate.format('MM-DD'),
            dayOfWeek: currentDate.format('ddd')
          })
          currentDate = currentDate.add(1, 'day')
        }
        return days
      }
    })
    
    const unitWidth = computed(() => {
      if (props.viewType === 'week') {
        return 150 * props.zoomLevel // 周视图宽度稍大
      } else {
        return 100 * props.zoomLevel // 日视图宽度
      }
    })
    
    const totalWidth = computed(() => timelineUnits.value.length * unitWidth.value)
    
    // 今天线位置
    const todayLinePosition = computed(() => {
      if (props.viewType === 'week') {
        return dayjs().diff(props.timelineStart, 'weeks') * unitWidth.value
      } else {
        return dayjs().diff(props.timelineStart, 'days') * unitWidth.value
      }
    })
    
    // 时间范围指示器
    const showTimeRangeIndicator = computed(() => {
      if (!props.timeRange || props.timeRange.length < 2) return false
      const [start, end] = props.timeRange
      return start.isBefore(end) && start.isBefore(props.timelineEnd) && end.isBefore(props.timelineEnd)
    })

    const timeRangeIndicatorLeft = computed(() => {
      if (!showTimeRangeIndicator.value) return 0
      const [start, end] = props.timeRange
      let startOffset
      if (props.viewType === 'week') {
        startOffset = start.diff(props.timelineStart, 'weeks')
      } else {
        startOffset = start.diff(props.timelineStart, 'days')
      }
      return startOffset * unitWidth.value
    })

    const timeRangeIndicatorWidth = computed(() => {
      if (!showTimeRangeIndicator.value) return 0
      const [start, end] = props.timeRange
      let startOffset, endOffset
      if (props.viewType === 'week') {
        startOffset = start.diff(props.timelineStart, 'weeks')
        endOffset = end.diff(props.timelineStart, 'weeks')
      } else {
        startOffset = start.diff(props.timelineStart, 'days')
        endOffset = end.diff(props.timelineStart, 'days')
      }
      return (endOffset - startOffset) * unitWidth.value
    })
    
    // 安全获取dayjs对象
    const getSafeDayjs = (date) => {
      if (!date) return null
      try {
        if (date.format && typeof date.format === 'function' && date.diff && typeof date.diff === 'function') {
          return date
        }
        const dayjsDate = dayjs(date)
        if (dayjsDate.isValid()) {
          return dayjsDate
        }
        return null
      } catch (error) {
        console.warn('日期转换失败:', error, date)
        return null
      }
    }
    
    // 计算任务位置
    const getTaskPosition = (task) => {
      if (!task || !props.tasks) {
        return {
          left: 0,
          width: 10,
          top: 10
        }
      }
      
      const startDate = getSafeDayjs(task.startDate)
      const endDate = getSafeDayjs(task.endDate)
      
      if (!startDate || !endDate) {
        return {
          left: 0,
          width: 10,
          top: 10
        }
      }
      
      let startOffset, duration
      if (props.viewType === 'week') {
        const weekIndex = timelineUnits.value.findIndex(week => 
          startDate.isSame(week.start, 'week') || 
          (startDate.isAfter(week.start) && startDate.isBefore(week.end)) ||
          startDate.isSame(week.start, 'day') ||
          startDate.isSame(week.end, 'day')
        )
        
        const endWeekIndex = timelineUnits.value.findIndex(week => 
          endDate.isSame(week.start, 'week') || 
          (endDate.isAfter(week.start) && endDate.isBefore(week.end)) ||
          endDate.isSame(week.start, 'day') ||
          endDate.isSame(week.end, 'day')
        )
        
        startOffset = weekIndex >= 0 ? weekIndex : 0
        duration = endWeekIndex >= 0 ? (endWeekIndex - weekIndex + 1) : 1
      } else {
        startOffset = startDate.diff(props.timelineStart, 'days')
        duration = endDate.diff(startDate, 'days') + 1
      }
      
      const taskIndex = props.tasks.findIndex(t => t.id === task.id)
      
      return {
        left: Math.max(0, startOffset * unitWidth.value),
        width: Math.max(10, duration * unitWidth.value),
        top: taskIndex * 50 + 10
      }
    }
    
    // 计算依赖连线
    const dependencyLines = computed(() => {
      const lines = []
      
      if (!props.tasks || props.tasks.length === 0) {
        return lines
      }
      
      props.tasks.forEach(task => {
        if (task.dependencies && task.dependencies.length > 0) {
          task.dependencies.forEach(depId => {
            const depTask = props.tasks.find(t => t.id === depId)
            if (depTask) {
              const depPos = getTaskPosition(depTask)
              const taskPos = getTaskPosition(task)
              
              const depTaskStyle = getTaskBarStyle(depTask)
              const taskStyle = getTaskBarStyle(task)
              
              const startX = depPos.left + parseFloat(depTaskStyle.width) + 10
              const endX = taskPos.left
              
              const depIndex = props.tasks.findIndex(t => t.id === depTask.id)
              const taskIndex = props.tasks.findIndex(t => t.id === task.id)
              const startY = depIndex * 50 + 25
              const endY = taskIndex * 50 + 25
              
              const controlPoint1X = startX + Math.max(50, (endX - startX) * 0.3)
              const controlPoint1Y = startY
              const controlPoint2X = endX - Math.max(50, (endX - startX) * 0.3)
              const controlPoint2Y = endY
              
              const path = `M ${startX} ${startY} C ${controlPoint1X} ${controlPoint1Y} ${controlPoint2X} ${controlPoint2Y} ${endX} ${endY}`
              
              lines.push({
                id: `${depId}-${task.id}`,
                path,
                fromTask: depTask,
                toTask: task
              })
            }
          })
        }
      })
      
      return lines
    })
    
    // 任务条样式
    const getTaskBarStyle = (task) => {
      if (!task || !props.tasks) {
        return {
          left: '0px',
          width: '10px',
          backgroundColor: '#909399'
        }
      }
      
      let startDate = getSafeDayjs(task.startDate)
      let endDate = getSafeDayjs(task.endDate)
      
      if (!startDate || !endDate) {
        return {
          left: '0px',
          width: '10px',
          backgroundColor: '#909399'
        }
      }
      
      // 如果是正在拖拽resize-start的任务，使用临时开始日期
      if (props.dragState.isDragging && 
          props.dragState.dragType === 'resize-start' && 
          props.dragState.draggedTask?.id === task.id &&
          props.dragState.tempStartDate) {
        startDate = props.dragState.tempStartDate
      }
      
      // 如果是正在拖拽resize-end的任务，使用临时结束日期
      if (props.dragState.isDragging && 
          props.dragState.dragType === 'resize-end' && 
          props.dragState.draggedTask?.id === task.id &&
          props.dragState.tempEndDate) {
        endDate = props.dragState.tempEndDate
      }
      
      let startOffset, duration
      if (props.viewType === 'week') {
        const weekIndex = timelineUnits.value.findIndex(week => 
          startDate.isSame(week.start, 'week') || 
          (startDate.isAfter(week.start) && startDate.isBefore(week.end)) ||
          startDate.isSame(week.start, 'day') ||
          startDate.isSame(week.end, 'day')
        )
        
        const endWeekIndex = timelineUnits.value.findIndex(week => 
          endDate.isSame(week.start, 'week') || 
          (endDate.isAfter(week.start) && endDate.isBefore(week.end)) ||
          endDate.isSame(week.start, 'day') ||
          endDate.isSame(week.end, 'day')
        )
        
        startOffset = weekIndex >= 0 ? weekIndex : 0
        duration = endWeekIndex >= 0 ? (endWeekIndex - weekIndex + 1) : 1
      } else {
        startOffset = startDate.diff(props.timelineStart, 'days')
        duration = endDate.diff(startDate, 'days') + 1
      }
      
      const taskIndex = props.tasks.findIndex(t => t.id === task.id)
      
      const position = {
        left: Math.max(0, startOffset * unitWidth.value),
        width: Math.max(10, duration * unitWidth.value),
        top: taskIndex * 50 + 10
      }
      
      const adjustedWidth = position.width - 10
      return {
        left: position.left + 'px',
        width: adjustedWidth + 'px',
        backgroundColor: getTaskColor(task)
      }
    }

    // 获取任务颜色
    const getTaskColor = (task) => {
      if (task.color) return task.color
      
      switch (task.status) {
        case 'completed':
          return '#67C23A'
        case 'in-progress':
          return '#409EFF'
        case 'pending':
          return '#E6A23C'
        case 'cancelled':
          return '#F56C6C'
        default:
          return '#909399'
      }
    }
    
    // 获取鼠标位置（考虑滚动偏移）
    const getMousePosition = (e) => {
      if (!timelineAreaRef.value) return { x: 0, daysOffset: 0 }
      
      const rect = timelineAreaRef.value.getBoundingClientRect()
      const scrollLeft = timelineAreaRef.value.scrollLeft || 0
      const x = e.clientX - rect.left + scrollLeft
      const daysOffset = Math.max(0, Math.round(x / unitWidth.value))
      
      return { x, daysOffset }
    }
    
    // 自动滚动处理
    const handleAutoScroll = (e) => {
      if (!timelineAreaRef.value) return
      
      const rect = timelineAreaRef.value.getBoundingClientRect()
      const mouseX = e.clientX - rect.left
      const scrollThreshold = 50
      const scrollSpeed = 10
      
      let direction = 0
      if (mouseX < scrollThreshold) {
        direction = -1 // 向左滚动
      } else if (mouseX > rect.width - scrollThreshold) {
        direction = 1 // 向右滚动
      }
      
      // 清除之前的定时器
      if (props.dragState.autoScrollInterval) {
        clearInterval(props.dragState.autoScrollInterval)
      }
      
      // 设置自动滚动定时器
      if (direction !== 0) {
        const autoScrollInterval = setInterval(() => {
          if (timelineAreaRef.value) {
            timelineAreaRef.value.scrollLeft += direction * scrollSpeed
          }
        }, 16)
        
        emit('task-drag-move', { autoScrollInterval })
      }
    }
    
    // 开始拖拽
    const startDrag = (e, task, type = 'move') => {
      e.preventDefault()
      e.stopPropagation()
      
      hideTooltip()
      
      const { x } = getMousePosition(e)
      
      // 设置拖拽状态
      const dragState = {
        isDragging: true,
        dragType: type,
        draggedTask: task,
        startX: x,
        startY: e.clientY,
        originalStartDate: task.startDate.clone(),
        originalEndDate: task.endDate.clone(),
        autoScrollInterval: null,
        tempEndDate: null,
        tempStartDate: null
      }
      
      // 发出拖拽开始事件
      emit('task-drag-start', {
        task,
        type,
        startX: x,
        startY: e.clientY,
        originalStartDate: task.startDate.clone(),
        originalEndDate: task.endDate.clone(),
        dragState
      })
      
      // 添加全局事件监听
      document.addEventListener('mousemove', handleDragMove)
      document.addEventListener('mouseup', handleDragEnd)
      
      // 添加拖拽样式
      document.body.style.cursor = 'grabbing'
      document.body.style.userSelect = 'none'
    }
    
    // 拖拽移动
    const handleDragMove = (e) => {
      const { x, daysOffset } = getMousePosition(e)
      const task = props.dragState.draggedTask
      const unit = props.viewType === 'week' ? 'weeks' : 'days'
      const offset = daysOffset
      
      if (props.dragState.dragType === 'move') {
        // 移动任务
        let diff
        if (props.viewType === 'week') {
          // 在周视图中，需要找到任务开始时间所在的周索引来计算偏移
          const currentWeekIndex = timelineUnits.value.findIndex(week => 
            task.startDate.isSame(week.start, 'week') || 
            (task.startDate.isAfter(week.start) && task.startDate.isBefore(week.end)) ||
            task.startDate.isSame(week.start, 'day') ||
            task.startDate.isSame(week.end, 'day')
          )
          diff = offset - (currentWeekIndex >= 0 ? currentWeekIndex : 0)
        } else {
          diff = offset - task.startDate.diff(props.timelineStart, unit)
        }
        
        const newStartDate = task.startDate.add(diff, unit)
        const newEndDate = task.endDate.add(diff, unit)
        
        if (newStartDate.isBefore(props.timelineStart)) return
        if (newEndDate.isAfter(props.timelineEnd)) return
        
        // 发出更新任务事件
        emit('task-drag-move', {
          taskId: task.id,
          updates: {
            startDate: newStartDate,
            endDate: newEndDate,
            viewType: props.viewType
          }
        })
      } else if (props.dragState.dragType === 'resize-start') {
        let newStartDate
        if (props.viewType === 'week') {
          // 在周视图中，根据offset找到对应的周开始时间
          if (offset >= 0 && offset < timelineUnits.value.length) {
            newStartDate = timelineUnits.value[offset].start.clone()
          } else {
            newStartDate = props.timelineStart.add(offset, unit)
          }
        } else {
          newStartDate = props.timelineStart.add(offset, unit)
        }
        
        if (newStartDate.isBefore(task.endDate) && newStartDate.isAfter(props.timelineStart.subtract(1, unit))) {
          // 使用临时开始日期，避免闪烁
          props.dragState.tempStartDate = newStartDate
        }
      } else if (props.dragState.dragType === 'resize-end') {
        let mouseEndDate
        if (props.viewType === 'week') {
          // 在周视图中，根据offset找到对应的周结束时间
          if (offset >= 0 && offset < timelineUnits.value.length) {
            mouseEndDate = timelineUnits.value[offset].end.clone()
          } else {
            mouseEndDate = props.timelineStart.add(offset, unit)
          }
        } else {
          mouseEndDate = props.timelineStart.add(offset, unit)
        }
        
        if (mouseEndDate.isAfter(task.startDate)) {
          const taskEndDate = mouseEndDate.subtract(1, unit)
          props.dragState.tempEndDate = taskEndDate
        }
      }
      
      handleAutoScroll(e)
    }

    const handleDragEnd = () => {
      if (props.dragState.autoScrollInterval) {
        clearInterval(props.dragState.autoScrollInterval)
        props.dragState.autoScrollInterval = null
      }
      
      // 处理 resize-start
      if (props.dragState.dragType === 'resize-start' && props.dragState.tempStartDate) {
        const task = props.dragState.draggedTask
        let newStartDate = props.dragState.tempStartDate
        
        if (newStartDate.isAfter(task.endDate)) {
          newStartDate = task.endDate
        }
        if (newStartDate.isBefore(props.timelineStart)) {
          newStartDate = props.timelineStart
        }
        
        emit('task-drag-end', {
          taskId: task.id,
          updates: { 
            startDate: newStartDate,
            viewType: props.viewType
          }
        })
      }
      
      // 处理 resize-end
      if (props.dragState.dragType === 'resize-end' && props.dragState.tempEndDate) {
        const task = props.dragState.draggedTask
        let newEndDate = props.dragState.tempEndDate
        
        if (newEndDate.isAfter(props.timelineEnd)) {
          newEndDate = props.timelineEnd
        }
        if (newEndDate.isBefore(task.startDate)) {
          newEndDate = task.startDate
        }
        
        emit('task-drag-end', {
          taskId: task.id,
          updates: { 
            endDate: newEndDate,
            viewType: props.viewType
          }
        })
      }
      
      document.removeEventListener('mousemove', handleDragMove)
      document.removeEventListener('mouseup', handleDragEnd)
      document.body.style.cursor = ''
      document.body.style.userSelect = ''
      
      // 发出拖拽结束事件
      emit('task-drag-end', {
        taskId: props.dragState.draggedTask?.id,
        dragState: {
          isDragging: false,
          dragType: null,
          draggedTask: null,
          startX: 0,
          startY: 0,
          originalStartDate: null,
          originalEndDate: null,
          autoScrollInterval: null,
          tempEndDate: null,
          tempStartDate: null
        }
      })
    }
    
    // 处理时间轴滚动
    const handleTimelineScroll = (e) => {
      emit('scroll', e)
    }
    
    // 任务选择
    const selectTask = (task) => {
      emit('task-select', task)
    }
    
    // 显示悬浮提示
    const showTooltip = (event, task) => {
      if (!task) return
      
      const rect = timelineAreaRef.value.getBoundingClientRect()
      const scrollLeft = timelineAreaRef.value.scrollLeft || 0
      const scrollTop = timelineAreaRef.value.scrollTop || 0
      
      let left = event.clientX - rect.left + scrollLeft + 10
      let top = event.clientY - rect.top + scrollTop - 10
      
      const tooltipWidth = 280
      const tooltipHeight = 200
      
      if (left + tooltipWidth > rect.width + scrollLeft) {
        left = event.clientX - rect.left + scrollLeft - tooltipWidth - 10
      }
      
      if (top + tooltipHeight > rect.height + scrollTop) {
        top = event.clientY - rect.top + scrollTop - tooltipHeight - 10
      }
      
      tooltip.value = {
        visible: true,
        task: task,
        style: {
          left: left + 'px',
          top: top + 'px'
        }
      }
      
      emit('tooltip-show', { task, style: tooltip.value.style })
    }
    
    // 隐藏悬浮提示
    const hideTooltip = () => {
      tooltip.value.visible = false
      tooltip.value.task = null
      emit('tooltip-hide')
    }
    
    // 监听拖拽状态变化，处理自动滚动
    watch(() => props.dragState.isDragging, (isDragging) => {
      if (isDragging) {
        document.addEventListener('mousemove', handleAutoScroll)
      } else {
        document.removeEventListener('mousemove', handleAutoScroll)
      }
    })
    
    // 监听父组件的滚动事件，同步时间线的垂直滚动
    watch(() => props.taskListScrollTop, (newScrollTop) => {
      if (timelineAreaRef.value) {
        timelineAreaRef.value.scrollTop = newScrollTop
      }
    })

    // 组件卸载时清理
    onMounted(() => {
      return () => {
        document.removeEventListener('mousemove', handleAutoScroll)
      }
    })
    
    return {
      timelineAreaRef,
      timelineUnits,
      unitWidth,
      totalWidth,
      dependencyLines,
      todayLinePosition,
      showTimeRangeIndicator,
      timeRangeIndicatorLeft,
      timeRangeIndicatorWidth,
      tooltip,
      getTaskPosition,
      getTaskBarStyle,
      getTaskColor,
      startDrag,
      handleDragMove,
      handleDragEnd,
      handleTimelineScroll,
      selectTask,
      showTooltip,
      hideTooltip
    }
  }
}
</script>

<style scoped>
.timeline-area {
  flex: 1;
  overflow-x: auto;
  overflow-y: hidden;
  position: relative;
  min-width: 0;
}

.timeline-content {
  position: relative;
}

.timeline-header-row {
  display: flex;
  background: #f0f0f0;
  border-bottom: 1px solid #d9d9d9;
  position: sticky;
  top: 0;
  z-index: 100;
  height: 50px;
  align-items: center;
  box-sizing: border-box;
  padding: 0;
}

.timeline-unit-header {
  text-align: center;
  padding: 4px 0;
  font-size: 12px;
  font-weight: 500;
  border-right: 1px solid #d9d9d9;
  flex-shrink: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

.unit-label {
  font-weight: 600;
  margin-bottom: 2px;
}

.unit-sub-label {
  font-size: 10px;
  color: #666;
  font-weight: normal;
}

.timeline-content-area {
  position: relative;
  background: repeating-linear-gradient(
    90deg,
    transparent,
    transparent calc(var(--unit-width, 100px) - 1px),
    #f0f0f0 calc(var(--unit-width, 100px) - 1px),
    #f0f0f0 var(--unit-width, 100px)
  );
  border-right: 1px solid #d9d9d9;
}

.dependency-lines {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 40;
}

.task-bar-container {
  position: absolute;
  height: 50px;
  width: 100%;
}

.task-bar {
  position: absolute;
  height: 30px;
  border-radius: 4px;
  cursor: grab;
  display: flex;
  align-items: center;
  padding: 0 8px;
  color: white;
  font-size: 12px;
  font-weight: 500;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: all 0.2s;
  user-select: none;
  top: 10px;
  overflow: hidden;
}

.task-bar:hover {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  transform: translateY(-1px);
}

.task-bar {
  position: relative;
}

.task-bar::after {
  content: "双击编辑";
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 10px;
  color: rgba(255, 255, 255, 0.8);
  opacity: 0;
  transition: opacity 0.2s;
  pointer-events: none;
  z-index: 5;
}

.task-bar:hover::after {
  opacity: 1;
}

.task-bar.dragging {
  cursor: grabbing;
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
  transform: translateY(-2px);
}

.task-bar-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  z-index: 1;
  position: relative;
}

.task-name {
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.task-progress {
  font-size: 10px;
  margin-left: 8px;
}

.task-progress-container {
  position: absolute;
  top: 0;
  left: 8px;
  right: 8px;
  height: 100%;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  pointer-events: none;
  box-sizing: border-box;
  overflow: hidden;
}

.task-progress-fill {
  height: 100%;
  background: rgba(255, 255, 255, 0.4);
  border-radius: 4px;
  pointer-events: none;
  box-sizing: border-box;
  transition: width 0.3s ease;
}

.today-line {
  position: absolute;
  top: 0;
  width: 2px;
  background: #f56c6c;
  z-index: 100;
}

.time-range-indicator {
  position: absolute;
  top: 0;
  background: rgba(64, 158, 255, 0.1);
  border-left: 2px solid #409EFF;
  border-right: 2px solid #409EFF;
  pointer-events: none;
  z-index: 50;
}

.resize-handle {
  position: absolute;
  width: 10px;
  height: 100%;
  top: 0;
  cursor: col-resize;
  z-index: 10;
}

.resize-start {
  left: -5px;
}

.resize-end {
  right: -5px;
}
</style> 